package com.levi.config;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.levi.pojo.SysMenu;
import com.levi.pojo.SysRole;
import com.levi.pojo.SysUser;
import com.levi.service.SysMenuService;
import com.levi.service.SysRoleService;
import com.levi.service.SysUserRoleService;
import com.levi.service.SysUserService;
import lombok.extern.slf4j.Slf4j;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.*;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;
import org.apache.shiro.subject.Subject;
import org.apache.shiro.util.ByteSource;
import org.springframework.beans.factory.annotation.Autowired;

import java.util.List;

/**
 * 自定义的realm，实现里面的两个方法，一个认证，一个授权
 */
@Slf4j
public class UserRealm extends AuthorizingRealm {
    @Autowired
    SysUserService userService;

    @Autowired
    SysUserRoleService userRoleService;

    @Autowired
    SysRoleService roleService;

    @Autowired
    SysMenuService menuService;

    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
//        log.info("执行了doGetAuthorizationInfo 授权方法");
        System.out.println("执行了doGetAuthorizationInfo 授权方法");
        SimpleAuthorizationInfo authorizationInfo = new SimpleAuthorizationInfo();

        Subject subject = SecurityUtils.getSubject();
        SysUser currentUser = (SysUser) subject.getPrincipal();
        //1.根据用户id查询出来用户所有的角色，然后进行遍历
        List<SysRole> roleList = roleService.listRoleByUserId(currentUser.getId());

        for (SysRole sysRole : roleList) {
            QueryWrapper<SysMenu> menuQueryWrapper = new QueryWrapper<>();
            menuQueryWrapper.eq("code", sysRole.getId());
            //2.根据用户的所有角色id遍历出用户所有的权限(菜单)
            List<SysMenu> sysMenuList = menuService.menuListByRoleId(sysRole.getId());
            for (SysMenu sysMenu : sysMenuList) {
                //3.进行授权，授权后return
                authorizationInfo.addStringPermission(sysMenu.getCode());
            }
        }
        return authorizationInfo;
    }

    /**
     * 用户认证的方法
     * @param authenticationToken
     * @return
     * @throws AuthenticationException
     */
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
//        log.info("执行了doGetAuthenticationInfo 认证方法");
        System.out.println("执行了doGetAuthenticationInfo 认证方法");
        UsernamePasswordToken userToken = (UsernamePasswordToken) authenticationToken;
      /*  //自定义用户名密码，测试用
        String username = "root";
        String password = "123456";
        if (!userToken.getUsername().equals(username)) {
            return null; //return null会抛出异常，抛出的异常是在Controller中捕获的异常 UnknownAccountException
        }*/


        //连接数据库测试用户名，密码
        QueryWrapper<SysUser> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("username", userToken.getUsername());
        SysUser sysUser = userService.getOne(queryWrapper);
        if (sysUser == null) {
            return null;  //如果用户为空 抛出异常，调用controller写的异常进行捕获
        }
        //
        //
        /**
         * 1.密码不需要手动验证，shiro自动帮我们做   return接口的一个实现类,封装一些属性
         * 2.密码也可以进行加密，md5，hash，sha256等等方法都可以进行加密
         * 3.把sysUser对象给封装进去，可以在授权方法中获取，根据sysUser对象的权限进行权限设置
         */
        return new SimpleAuthenticationInfo(sysUser,//用户对象
                sysUser.getPassword(),//密码
                ByteSource.Util.bytes(""),//加盐
                "");
    }
}
